import Tile from './Tile'
import { getPxFromLngLat, getTileRowAndCol, px2Mercator, mercator2lngLat, lngLat2Mercator,TILE_SIZE } from '../utils'
class ZMap {
  constructor(el, options) {
    const mountEl = document.getElementById(el)
    const { width, height } = mountEl.getBoundingClientRect()
    this.width = width
    this.height = height
    this.mountEl = mountEl
    // 设置默认的坐标原点和缩放比例
    this.options = {
      center: [0, 0],
      zoom: 16,
      ...options
    }
    this.minZoom = 3
    this.maxZoom = 18
    // 存储缓存的瓦片
    this.tileCache = {}
    // 创建绘制瓦片的canvas
    this.canvas = this.initCanvas()
    //  绘制瓦片
    this.renderTile()
    // 添加事件移动和缩放事件
    this.addEvent()
  }
  initCanvas() {
    const canvas = document.createElement('canvas')
    canvas.width = this.width
    canvas.height = this.height
    this.mountEl.appendChild(canvas)
    this.ctx = canvas.getContext('2d')
    // 移动画布原点到画布中间，原点向右->为x轴正方形，原点向下为Y轴正方形
    this.ctx.translate(this.width / 2, this.height / 2);
    return canvas
  }
  renderTile() {
    const { center, zoom } = this.options
    // 获取中心点瓦片行列号
    const centerTile = getTileRowAndCol(...lngLat2Mercator(...center), zoom)
    // 中心瓦片左上角的像素坐标
    const centerTilePxPos = [centerTile[0] * TILE_SIZE, centerTile[1] * TILE_SIZE]
    // 中心点像素坐标，（canvas原点位置）
    const centerPxPos = getPxFromLngLat(...center, zoom)
    //中心像素坐标距中心瓦片左上角的差值
    const offset = [
      centerPxPos[0] - centerTilePxPos[0],
      centerPxPos[1] - centerTilePxPos[1]
    ]

    // 绘制范围内的所有瓦片
    // 计算瓦片数量
    let rowMinNum = Math.ceil((this.width / 2 - offset[0]) / TILE_SIZE)// 左
    let colMinNum = Math.ceil((this.height / 2 - offset[1]) / TILE_SIZE)// 上
    let rowMaxNum = Math.ceil((this.width / 2 - (TILE_SIZE - offset[0])) / TILE_SIZE)// 右
    let colMaxNum = Math.ceil((this.height / 2 - (TILE_SIZE - offset[1])) / TILE_SIZE)// 下

    // 从上到下，从左到右，加载瓦片
    for (let i = -rowMinNum; i <= rowMaxNum; i++) {
      for (let j = -colMinNum; j <= colMaxNum; j++) {
        // 加载瓦片图片
        const x = i * TILE_SIZE - offset[0]
        const y = j * TILE_SIZE - offset[1]
        const row = centerTile[0] + i// 行号
        const col = centerTile[1] + j// 列号
        const cacheKey = `${row}-${col}-${zoom}`
        if (this.tileCache[cacheKey]) {
          this.tileCache[cacheKey].updatePos(x, y).render()
        } else {
          this.tileCache[cacheKey] = new Tile({
            ctx: this.ctx,
            x,
            y,
            row,
            col,
            zoom
          })
        }
      }
    }
  }
  
  clear() {
    this.ctx.clearRect(-this.width / 2, -this.height / 2, this.width, this.height)
    // 不加这个之前绘制的react在stroke之后又都会出来
    this.ctx.beginPath()
  }

  addEvent() {
    this.canvas.addEventListener('mousedown', this.mousedown.bind(this))
    this.canvas.addEventListener('mouseup', this.mouseup.bind(this))
    this.canvas.addEventListener('mousemove', this.mousemove.bind(this))
    this.canvas.addEventListener('wheel', this.wheel.bind(this))

  }
  mousedown(e) {
    if (e.which === 1) {
      this._moved = true
    }
  }
  mouseup(e) {
    this._moved = false
  }
  mousemove(e) {
    if (!this._moved) {
      return
    }
    this.onMove(e.movementX, e.movementY)
    this._moveEnd = false
  }
  wheel(e) {
    const { zoom } = this.options
    if (e.deltaY > 0) {
      // 层级变小
      if (zoom > this.minZoom) {
        this.options.zoom--
      }
    } else {
      if (zoom < this.maxZoom) {
        this.options.zoom++
      }
    }
    if (this.options.zoom === zoom) {
      return
    }
    this.onZoom()
  }
  onMove(moveX, moveY) {
    const { zoom, center } = this.options
    const [mx, my] = px2Mercator(moveX, moveY, zoom)
    const [x, y] = lngLat2Mercator(...center)
    // 更新拖动后的中心点经纬度
    const newCenter = mercator2lngLat(x - mx, my + y);
    this.options.center = newCenter
    this.clear()
    this.renderTile()
  }
  onZoom() {
    this.timer = setTimeout(() => {
      if (this.timer) clearTimeout(this.timer)
      this.clear()
      this.renderTile()
    }, 300)
  }
}

export default ZMap